﻿#include "crcCheck.h"

/**
 * @brief crcCheck::calculate_crc8(const QByteArray &data, uint8_t poly, uint8_t init)
 * @param data 输入数据（QByteArray）
 * @param poly 多项式（默认 0x07）
 * @param init 初始值（默认 0x00）
 * @return CRC-8 校验值
 * @author yuluo
 * @details 计算 QByteArray 的 CRC-8
 */
uint8_t crcCheck::calculate_crc8(const QByteArray &data, uint8_t poly, uint8_t init)
{
    /* 调用底层的函数直接计算 */
    return calculate_crc8(reinterpret_cast<const uint8_t *>(data.constData()), data.size(), poly, init);
}

/**
 * @brief crcCheck::calculate_crc8(const uint8_t *data, int length, uint8_t poly, uint8_t init)
 * @param data 输入数据指针
 * @param length 数据长度（字节数）
 * @param poly 多项式（默认 0x07）
 * @param init 初始值（默认 0x00）
 * @return CRC-8 校验值
 * @author yuluo
 * @details 计算原始字节数组的 CRC-8
 *
 *  * 算法原理：
 *   1. 初始值赋给 crc
 *   2. 遍历数据，每个字节依次与 crc 异或
 *   3. 对每个字节执行 8 次循环：
 *        - 如果最高位为 1，则左移一位后与 poly 异或
 *        - 否则直接左移一位
 *   4. 最终得到的 8 位值即为 CRC-8 校验码
 */
uint8_t crcCheck::calculate_crc8(const uint8_t *data, int length, uint8_t poly, uint8_t init)
{
    uint8_t crc = init;

    for(int i = 0; i < length; i++)
    {
        /* 将数据与 CRC 当前值异或 */
        crc ^= data[i];
        for(int j = 0; j < 8; j++)
        {
            /* 判断最高位是否为 1 */
            if(crc & 0x80)
            {
                crc = (crc << 1) ^ poly;
            }
            else
            {
                crc <<= 1;
            }
        }
    }
    return crc;
}

/**
 * @brief crcCheck::calculate_crc32(const QByteArray &data, uint32_t poly, uint32_t init, uint32_t xorOut, bool refIn, bool refOut)
 * @param data 输入数据（QByteArray）
 * @param poly 多项式
 * @param init 初始值
 * @param xorOut 输出异或值
 * @param refIn 是否反转输入字节
 * @param refOut 是否反转输出 CRC
 * @return CRC-32 校验值
 * @author yuluo
 * @details 计算 QByteArray 的 CRC-32
 */
uint32_t crcCheck::calculate_crc32(const QByteArray &data, uint32_t poly, uint32_t init, uint32_t xorOut, bool refIn, bool refOut)
{
    return calculate_crc32(reinterpret_cast<const uint8_t*>(data.constData()), data.size(), poly, init, xorOut, refIn, refOut);
}

/**
 * @brief crcCheck::calculate_crc32(const uint8_t *data, int length, uint32_t poly, uint32_t init, uint32_t xorOut, bool refIn, bool refOut)
 * @param data 输入数据指针
 * @param length 数据长度
 * @param poly 多项式
 * @param init 初始值
 * @param xorOut 输出异或值
 * @param refIn 是否反转输入字节
 * @param refOut 是否反转输出 CRC
 * @return CRC-32 校验值
 * @author yuluo
 * @details 计算原始字节数组的 CRC-32
 *
 *  * 算法步骤：
 *   1. 将 CRC 初始化为 init
 *   2. 遍历每个字节：
 *        - 如果 refIn = true，则先反转字节位序
 *        - 将该字节与 CRC 最高字节异或
 *        - 执行 8 次循环：
 *            - 若最高位为 1，则左移一位并异或 poly
 *            - 否则仅左移一位
 *   3. 遍历结束后，如果 refOut = true，则反转 CRC 位序
 *   4. 最终结果与 xorOut 异或，得到 CRC 值
 *
 */
uint32_t crcCheck::calculate_crc32(const uint8_t *data, int length, uint32_t poly, uint32_t init, uint32_t xorOut, bool refIn, bool refOut)
{
    uint32_t crc = init;

    for (int i = 0; i < length; i++)
    {
        uint8_t byte = data[i];
        if (refIn)
        {
            byte = static_cast<uint8_t>(reflect(byte, 8));
        }
        crc ^= (static_cast<uint32_t>(byte) << 24);

        for (int j = 0; j < 8; j++)
        {
            if (crc & 0x80000000)
                crc = (crc << 1) ^ poly;
            else
                crc <<= 1;
        }
    }

    if (refOut) {
        crc = reflect(crc, 32);
    }

    return crc ^ xorOut;
}

/**
 * @brief crcCheck::reflect(uint32_t value, int bits)
 * @param value 输入的值
 * @param bits  需要反转的位数
 * @return 反转后的值
 * @author yuluo
 * @details 按位反转函数
 * 示例：
 *   reflect(0b00010010, 8) = 0b01001000
 */
uint32_t crcCheck::reflect(uint32_t value, int bits)
{
    uint32_t result = 0;
    for (int i = 0; i < bits; i++)
    {
        if (value & 1)
        {
            result |= (1u << (bits - 1 - i));
        }
        value >>= 1;
    }
    return result;
}


